package com.question.poi;

import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMath;
import org.openxmlformats.schemas.officeDocument.x2006.math.CTOMathPara;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

/**
 * 可以把公式和XWPFRun按顺序遍历，用到了以CTP开头的底层方式
 * <p>
 * XWPFParagraph中主有两个方法可以分别提出XWPFRun和CTOMath，但是不知道位置
 * ParagraphChildOrderManager这个类是专门解决这个问题的
 *
 * @author : ywb
 * @createdDate : 2020/9/16
 * @updatedDate
 */
public class ParagraphChildOrderManager {

    public static int TYPE_RUN = 1;
    public static int TYPE_OMATH = 2;

    List<Integer> typeList = new ArrayList<Integer>();
    XWPFParagraph p;

    public ParagraphChildOrderManager(XWPFParagraph paragraph) {
        this.p = paragraph;
        //using a cursor to go through the paragraph from top to down
        XmlCursor xmlcursor = paragraph.getCTP().newCursor();
        while (xmlcursor.hasNextToken()) {
            XmlCursor.TokenType tokenType = xmlcursor.toNextToken();
            if (tokenType.isStart()) {
                if (xmlcursor.getName().getPrefix().equalsIgnoreCase("w") && xmlcursor.getName().getLocalPart().equalsIgnoreCase("r")) {
                    typeList.add(TYPE_RUN);
                } else if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("oMath")) {
                    typeList.add(TYPE_OMATH);
                }
            } else if (tokenType.isEnd()) {
                xmlcursor.push();
                xmlcursor.toParent();
                if (xmlcursor.getName().getLocalPart().equalsIgnoreCase("p")) {
                    break;
                }
                xmlcursor.pop();
            }
        }
    }

    public List<Object> getChildList() {
        List<Object> runsOrMathList = new ArrayList<Object>();
        List<XWPFRun> runs = p.getRuns();
        List<CTOMath> oMathList = p.getCTP().getOMathList();

//        Queue<Object> mathQueue = null;
        if (oMathList != null && oMathList.size() > 0) {
            Queue<XWPFRun> runsQueue = new LinkedList<XWPFRun>(runs);
            Queue<CTOMath> mathQueue = new LinkedList<CTOMath>(oMathList);

            for (int i = 0; i < typeList.size(); i++) {
                Integer type = typeList.get(i);
                if (type.equals(TYPE_RUN) && runs.size() > 0) {

                    runsOrMathList.add(runsQueue.poll());
                } else if (type.equals(TYPE_OMATH) && mathQueue.size() > 0) {
                    runsOrMathList.add(mathQueue.poll());
                }
            }
            return runsOrMathList;
        } else {
            List<CTOMathPara> oMathParaList = p.getCTP().getOMathParaList();
            Queue<XWPFRun> runsQueue = new LinkedList<XWPFRun>(runs);
            Queue<CTOMathPara> mathQueue = new LinkedList<CTOMathPara>(oMathParaList);
            for (int i = 0; i < typeList.size(); i++) {
                Integer type = typeList.get(i);
                if (type.equals(TYPE_RUN) && runs.size() > 0) {
                    runsOrMathList.add(runsQueue.poll());
                } else if (type.equals(TYPE_OMATH) && mathQueue.size() > 0) {
                    runsOrMathList.add(mathQueue.poll());
                }
            }
            return runsOrMathList;
        }
    }
}
